home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Compilers⁄Interps / kevoSource / kernel.c < prev    next >
Text File  |  1993-05-13  |  6KB  |  230 lines

  1. /* Kevo -- a prototype-based object-oriented language */
  2. /* (c) Antero Taivalsaari 1991-1993                   */
  3. /* Some parts (c) Antero Taivalsaari 1986-1988           */
  4. /* kernel.c: Lowest-level internals                      */
  5.  
  6. #include "global.h"
  7. #include "portGlobal.h"
  8.  
  9. /*--------------------------------------------------------------------------*/
  10. /* Primitive stack operations                            */
  11.  
  12. /*
  13.    These definitions are the most primitive internals. They are
  14.    not visible to the user, but they are convenient in other
  15.    definitions.
  16. */ 
  17.  
  18. /* 
  19.    To enable multitasking, stacks are allocated from the heap,
  20.    which makes the following operations a bit more complicated.
  21.    For safety, each stack is assumed to have an underflow area.
  22.  
  23.    Note that in the current implementation, stacks grow upwards
  24.    so they can be resized flexibly at runtime.
  25. */
  26. /* Return the address of data stack top */
  27. int* dataStackBottom()
  28. {
  29.   /* Access the data stack field in the task data area */
  30.   OBJECT* stack = (*up)->dataStack;
  31.   /* Return the bottom address, taking into account the underflow area */
  32.   return((int*)((int*)stack->mfa + DATAOFFSET + UNDERFLOWRESERVE - 1));
  33. }    
  34.  
  35.  
  36. int** returnStackBottom()
  37. {
  38.   /* Access the return stack field in the task data area */
  39.   OBJECT* stack = (*up)->returnStack;
  40.   /* Return the bottom address, taking into account the underflow area */
  41.   return((int**)((int*)stack->mfa + DATAOFFSET + UNDERFLOWRESERVE - 1));
  42. }    
  43.  
  44.  
  45. int** contextStackBottom()
  46. {
  47.   /* Access the context stack field in the task data area */
  48.   OBJECT* stack = (*up)->contextStack;
  49.   /* Return the bottom address, taking into account the underflow area */
  50.   return((int**)((int*)stack->mfa + DATAOFFSET + UNDERFLOWRESERVE - 1));
  51. }    
  52.  
  53.  
  54. void resetData()
  55. {
  56.   dataSp = dataStackBottom();
  57. }
  58.  
  59.  
  60. void resetReturn()
  61. {
  62.   returnSp = returnStackBottom();
  63. }
  64.  
  65.  
  66. void resetContext()
  67. {
  68.   contextSp = contextStackBottom();
  69. }
  70.  
  71.  
  72. /* initStacks(): initialize execution stacks */
  73. void initStacks()
  74. {
  75.   resetData();
  76.   resetReturn();
  77.   resetContext();
  78. }
  79.  
  80.  
  81. /*---------------------------------------------------------------------------*/
  82. /* Inner interpreters/multitaskers */ 
  83.  
  84. /*
  85.    These are not visible to the user either. They, however, constitute the
  86.    heart of the whole Kevo system, and the runtime efficiency of the system 
  87.    depends fundamentally on them.
  88. */
  89.  
  90. /* This is the heart of the multitasker: task switcher */
  91. /* Note that task will be switched only if multitasking is allowed */
  92. void yield()
  93. {
  94.     /* Event loop must be executed if enough time has passed */
  95.     /* yyy warning: this line of code is non-portable */
  96.  
  97.     if (TickCount() >= nextTime) EventLoop();
  98.  
  99.     /* If multitasking, switch task */
  100.     if (multitasking) {
  101.         /* This code is the equivalent of 'yieldTo((*up)->nextInRobin)' */
  102.         /* see 'tasks.c'. For efficiency, the code has been "inlined"   */
  103.  
  104.         nPushReturn(3);    /* Macro: push three items to return stack */
  105.         thirdReturn  = (int*)contextSp;
  106.         secondReturn = (int*)dataSp;
  107.         topReturn    = (int*)ip;
  108.         (*up)->rpStore = returnSp;
  109.  
  110.         up = (*up)->nextInRobin;    /* Task switch!!! */
  111.         
  112.         returnSp  = (*up)->rpStore;
  113.         ip          = (int**)topReturn;
  114.         dataSp      = secondReturn;
  115.         contextSp = (int**)thirdReturn;
  116.         nPopReturn(3);    /* Macro: pop three items from return stack */
  117.     }
  118.  
  119.     /* Load new time slice */ 
  120.     slice = (*up)->priority;
  121. }
  122.  
  123.  
  124. /* This is the big kabloona: preemptive inner interpreter/multitasker */
  125.  
  126. /*
  127.     Remember: due to having to keep track of the pointer to the last 
  128.     object handle ('op'), it is important that task switches cannot occur 
  129.     when going from a high-level operation to a primitive.
  130.  
  131.     Therefore, in the current implementation 'yield()' can be called
  132.     only right after executing a primitive.
  133. */
  134.  
  135. void preemptiveInterpreter()
  136. {
  137.   register OBJECT* object;
  138.  
  139.     fprintf(confile, "Kevo running.\n");
  140.   
  141.     /* Store environment so that we can return here later */
  142.     (void)setjmp(p_inner);
  143.  
  144.     mtaskMode = PREEMPTIVE;
  145.     traceMode = NOTRACE;
  146.     supervisor = FALSE;
  147.   
  148.     slice = (*up)->priority;
  149.     while(TRUE) {
  150.  
  151.         /* High-level word (size field <> zero)? */
  152.         if ((object = (OBJECT*)*ip++)->sfa) {
  153.             pushReturn((int*)ip);
  154.             ip = (int**)(op = object)->mfa;
  155.         }
  156.         /* else invoke primitive */
  157.         else {
  158.             ((void (*)())object->mfa)();
  159.  
  160.             /* Decrement time slice */
  161.             if (--slice <= 0) yield(); 
  162.         }
  163.     }
  164. }
  165.  
  166.  
  167. /* This is another kabloona: cooperative inner interpreter. */
  168. /* This is about 20-30% faster than the preemptive one, because no slice */
  169. /* counter is needed, but on the other hand operations like loops block */
  170. /* the execution of other tasks (requires cooperation from all the tasks). */
  171.  
  172. /* In many cases preemptive interpreter may seem faster to the user, */
  173. /* because cooperative multitasking requires that all tasks are relatively */
  174. /* equal in their demand for computing power. */
  175.  
  176. /* Note: most I/O commands in Kevo contain a call to 'yield()', so as long */
  177. /* as a task does I/O, it is automatically guaranteed to cooperate with */
  178. /* other tasks. */
  179.  
  180. void cooperativeInterpreter()
  181. {
  182.   register OBJECT* object;
  183.  
  184.     /* Store environment so that we can return here later */
  185.     (void)setjmp(c_inner);    
  186.  
  187.     mtaskMode = COOPERATIVE;
  188.     traceMode = NOTRACE;
  189.     supervisor = FALSE;
  190.  
  191.     while(TRUE) {
  192.  
  193.         /* High-level word (size field <> zero)? */
  194.         if ((object = (OBJECT*)*ip++)->sfa) {
  195.             pushReturn((int*)ip);
  196.             ip = (int**)(op = object)->mfa;
  197.         }
  198.         /* else invoke primitive */
  199.         else ((void (*)())object->mfa)();
  200.     }
  201. }
  202.  
  203.  
  204. /* This version of longjmp automatically restores the correct environment */ 
  205.  
  206. void ownLongJmp()
  207. {
  208.     if (mtaskMode == PREEMPTIVE) longjmp(p_inner, TRUE);
  209.     else longjmp(c_inner, TRUE);
  210. }
  211.  
  212.  
  213. /* This execution operation is needed in many other primitive definitions */
  214. /* Executes a high-level or primitive object */
  215. void execute(object)
  216. OBJECT* object;
  217. {
  218.     if (object->sfa) {    
  219.         /* Execute a high-level definition */
  220.         pushReturn((int*)ip);
  221.         ip = (int**)(op = object)->mfa;
  222.         /* Due to 'op', task should never be switched right after */
  223.         /* executing a high-level operation */
  224.         slice++; 
  225.     }
  226.         /* Execute primitive */
  227.     else ((void (*)())object->mfa)();
  228. }
  229.  
  230.